package cn.edu.scau.cmi.liangzaoqing.fxml;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.apache.metamodel.schema.Column;
import org.apache.metamodel.schema.Schema;
import org.apache.metamodel.schema.Table;

import cn.edu.scau.cmi.liangzaoqing.database.model.ColumnType;
import cn.edu.scau.cmi.liangzaoqing.database.model.DataBaseType;
import cn.edu.scau.cmi.liangzaoqing.database.model.ModelType;
import cn.edu.scau.cmi.liangzaoqing.database.model.ObjectFactory;
import cn.edu.scau.cmi.liangzaoqing.database.model.PackageType;
import cn.edu.scau.cmi.liangzaoqing.database.model.PhysicalPrimaryKeysType;
import cn.edu.scau.cmi.liangzaoqing.database.model.Project;
import cn.edu.scau.cmi.liangzaoqing.database.model.TableType;
import cn.edu.scau.cmi.liangzaoqing.database.model.TablesType;
import cn.edu.scau.cmi.liangzaoqing.domain.LeafNode;
import cn.edu.scau.cmi.liangzaoqing.domain.MiddleNode;
import cn.edu.scau.cmi.liangzaoqing.domain.RootNode;
import cn.edu.scau.cmi.liangzaoqing.util.DatabaseMetaDataOutputUtil;
import cn.edu.scau.cmi.liangzaoqing.util.XmlToBeanUtil;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.Label;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class PhysicalPrimaryKeySelectController implements Initializable {

	private Map<String, String> databaseInfo;

	private Schema schema;

	@FXML
	private Button generateButton;
	@FXML
	private Label physicalPrimaryKeyTips;
	@FXML
	private TreeView treeView;

	@Override
	public void initialize(URL location, ResourceBundle resources) {
		// TODO Auto-generated method stub
		
	}
	//根据物理主键.xml文件和新表默认物理主键选择规则自动设置物理主键，初始化物理主键树。唐锦文
	//最终写入xml生成文件的物理主键与界面选择的物理主键一致，这里只是自动初始化。
	@SuppressWarnings("unchecked")
	public void initTreeView() throws JAXBException, IOException {
		String physicalPKXmlFilePath = databaseInfo.get("physicalPKXmlFilePath");
		if(physicalPKXmlFilePath.equals("")) {
			physicalPrimaryKeyTips.setText("您未选择物理主键文件，请手动为每个表选择物理主键！");
		}else {
			physicalPrimaryKeyTips.setTextFill(Color.BLUE);
			physicalPrimaryKeyTips.setText("已选物理主键文件："+physicalPKXmlFilePath.substring(physicalPKXmlFilePath.lastIndexOf("\\")+1));
		}
		Project project = XmlToBeanUtil.getProject(databaseInfo.get("physicalPKXmlFilePath"));
		CheckBoxTreeItem<String> root = new CheckBoxTreeItem<>();
		root.setExpanded(true);
		root.setValue(schema.getName());
		treeView.setCellFactory(CheckBoxTreeCell.forTreeView());
		treeView.setRoot(root);
		for (Table eachTable : schema.getTables()) {
			CheckBoxTreeItem<String> item = new CheckBoxTreeItem<>();
			item.setValue(eachTable.getName());
			root.getChildren().add(item);
			System.out.println("开始打印" + eachTable.getName() + "表的列的内容：" + eachTable.getColumnCount());
			//如果在物理主键.xml文件中已经有该表，则按照该文件自动选择物理主键。唐锦文
			if(null!=project && !isNewTable(project,eachTable.getName())) {
				TableType responseTableType = getResponseTable(project, eachTable.getName());
				PhysicalPrimaryKeysType physicalPrimaryKeys = responseTableType.getPhysicalPrimaryKeys();
				for(Column eachColumn : eachTable.getColumns()) {
					CheckBoxTreeItem<String> leaf = new CheckBoxTreeItem<>();
					leaf.setValue(eachColumn.getName());
					item.getChildren().add(leaf);
					for(ColumnType col:physicalPrimaryKeys.getColumn()) {
						if(eachColumn.getName().equalsIgnoreCase(col.getName())) {
							leaf.setSelected(true);
						}
					}
				}
			}else {//如果是新表，则按照默认规则选择物理主键，即有外键的外键为物理主键，没有外键的name属性为物理主键，有限制！！！！不通用
				//project为空表示该数据库是第一次生成xml文件，需要人为指定物理主键，应该在页面加提示
				for (Column eachColumn : eachTable.getColumns()) {
					CheckBoxTreeItem<String> leaf = new CheckBoxTreeItem<>();
					leaf.setValue(eachColumn.getName());
					item.getChildren().add(leaf);
					if (eachTable.getForeignKeys().length == 0) {
						if (eachColumn.getName().equalsIgnoreCase("name")) {
							leaf.setSelected(true);
						}
					} else {
						for (Column foreignCo : eachTable.getForeignKeys()) {
							if (eachColumn.getName().equalsIgnoreCase(foreignCo.getName())) {
								leaf.setSelected(true);
							}
						}
					}
					System.out.println(eachColumn.getName());
				}
			}
		}
	}

	public void setDatabaseInfo(Map<String, String> databaseInfo) {
		this.databaseInfo = databaseInfo;
	}

	public void setSchema(Schema schema) {
		this.schema = schema;
	}

	
	public TableType getResponseTable(Project project, String searchTableName) {
		for (TableType table : project.getModel().getDatabase().getTables().getTable()) {
			if (table.getName().equalsIgnoreCase(searchTableName)) {
				return table;
			}
		}
		return null;
	}
	
	//RootNode==Schema MiddleNode==Table LeafNode==Column
	//节点以树形方式组织数据，与树形物理主键选择界面对应。唐锦文
	//初始化节点树，该节点树在后面为物理主键字段填充数据。这里还没有最终选出物理主键。
	public RootNode getRootNode(Schema schema) {
		RootNode rootNode = new RootNode();
		rootNode.setName(schema.getName());
		for (Table eachTable : schema.getTables()) {
			MiddleNode middleNode = new MiddleNode();
			middleNode.setName(eachTable.getName());
			for (Column eachColumn : eachTable.getColumns()) {
				LeafNode leafNode = new LeafNode();
				leafNode.setName(eachColumn.getName());
				leafNode.setType(eachColumn.getNativeType());
				middleNode.getLeafItems().add(leafNode);
			}
			rootNode.getMiddleItems().add(middleNode);
		}
		return rootNode;
	}
	//根据物理主键选择界面选择的物理主键进一步初始化节点树，即将节点树中非物理主键的column置null，筛选出物理主键
	public RootNode getRootNodeForTree(RootNode rootNode, TreeView tree) {
		CheckBoxTreeItem<String> rootItem = (CheckBoxTreeItem<String>) tree.getRoot();
		CheckBoxTreeItem<String> middleItem = null;
		MiddleNode middleNode = null;
		CheckBoxTreeItem<String> leafItem = null;
		LeafNode leafNode = null;
		for (int i = 0; i < rootItem.getChildren().size() && i < rootNode.getMiddleItems().size(); i++) {
			middleNode = rootNode.getMiddleItems().get(i);
			middleItem = (CheckBoxTreeItem<String>) rootItem.getChildren().get(i);

			for (int j = 0; j < middleItem.getChildren().size() && j < middleNode.getLeafItems().size(); j++) {
				leafItem = (CheckBoxTreeItem<String>) middleItem.getChildren().get(j);
				leafNode = middleNode.getLeafItems().get(j);
				if (leafItem != null && leafNode != null && !leafItem.isSelected()) {
					leafNode.setName(null);
					leafNode.setType(null);
				}
			}
		}
		return rootNode;
	}

	public boolean isNewTable(Project project, String searchTableName) {
		for (TableType table : project.getModel().getDatabase().getTables().getTable()) {
			if (table.getName().equalsIgnoreCase(searchTableName)) {
				return false;
			}
		}
		return true;
	}
	
	public void beginGenerate() throws IOException {
		Schema chosenSchema = schema;
		DatabaseMetaDataOutputUtil metaData = new DatabaseMetaDataOutputUtil(databaseInfo.get("databaseType"),
				databaseInfo.get("ip"), databaseInfo.get("port"), schema.getName(), databaseInfo.get("username"),
				databaseInfo.get("password"));
		xmlGenerateBegin(metaData, schema.getName(), chosenSchema);
	}

	public void xmlGenerateBegin(DatabaseMetaDataOutputUtil metaData, String schemaName, Schema chosenSchema)
			throws IOException {

		ObjectFactory objFactory = new ObjectFactory();

		JAXBContext jc;
		try {
			jc = JAXBContext.newInstance("cn.edu.scau.cmi.liangzaoqing.database.model");
			// Unmarshaller u = jc.createUnmarshaller();
			// 通配符<?>的使用是不再报错。
			// JAXBElement<?> poElement = (JAXBElement<?>) u.unmarshal(new File(
			// "NewXMLSchema.xml"));

//			SchemaType schema = objFactory.createSchemaType();

			Project project = objFactory.createProject();
			PackageType packages = objFactory.createPackageType();
			ModelType model = objFactory.createModelType();
			TablesType tables = objFactory.createTablesType();
			DataBaseType dataBaseType = objFactory.createDataBaseType();

			// 添加项目名称
			project.setName(databaseInfo.get("project"));
			project.setFramework(databaseInfo.get("framework").toLowerCase());

			// 添加包名称
			packages.setName(databaseInfo.get("package"));
			// 添加数据库信息
			dataBaseType.setIp(databaseInfo.get("ip"));
			dataBaseType.setName(databaseInfo.get("databaseType"));
			dataBaseType.setPort(databaseInfo.get("port"));
			dataBaseType.setUsername(databaseInfo.get("username"));
			dataBaseType.setPassword(databaseInfo.get("password"));
			dataBaseType.setSchema(schemaName);

			List<TableType> tabletypes = tables.getTable();
			System.out.println("调用writeDataToXMl方法");
			RootNode node = getRootNode(schema);
			System.out.println("调用getRootNode方法");
			RootNode rootNode = getRootNodeForTree(node, treeView);
			System.out.println("调用getRootNodeForTree方法");
			try {
				tabletypes = metaData.getXmlTableSchema(chosenSchema, tabletypes, rootNode);
				System.out.println("调用getXmlTableSchema方法");
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			tables.setTable(tabletypes);
			System.out.println("调用writeDataToXMl方法结束");

			Marshaller m = jc.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化
			OutputStream os;
			SimpleDateFormat time = new SimpleDateFormat("-yyyyMMdd-HHmm");
			String timeString = time.format(System.currentTimeMillis());
			try {

				File file = new File(databaseInfo.get("genarateXmlFileDirectoryPath") + "/"
						+ databaseInfo.get("project") + timeString + ".xml");
				os = new FileOutputStream(file);
				dataBaseType.setTables(tables);
				model.setDatabase(dataBaseType);
				project.setModel(model);
				project.setPackage(packages);
				m.marshal(project, os);

				Stage nextStage = new Stage();
				nextStage.setTitle("数据库物理模型创建应用");
				FXMLLoader loader = new FXMLLoader(getClass().getResource("GenarateXmlFileSuccessPage.fxml"));
				Pane nextPane = loader.load();
				GenarateXmlFileSuccessController genarateXmlFileSuccessController = (GenarateXmlFileSuccessController) loader
						.getController();
				genarateXmlFileSuccessController
						.changeLabelContent("XML文件生成成功，请查看" + databaseInfo.get("genarateXmlFileDirectoryPath") + "\\"
								+ databaseInfo.get("project") + ".xml");
				Scene nextScene = new Scene(nextPane);
				nextStage.setScene(nextScene);
				nextStage.show();
				Stage stage = (Stage) generateButton.getScene().getWindow();
				stage.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
